<?php


declare (strict_types=1);

namespace app\api\service\passport;

use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Exception;
use app\api\model\{User as UserModel};
use app\api\service\{User as UserService};
use app\api\validate\passport\Login as ValidateLogin;
use app\common\service\BaseService;
use cores\exception\BaseException;
use think\facade\Cache;

/**
 * 服务类：用户登录
 * Class Login
 * @package app\api\service\passport
 */
class Login extends BaseService
{
    const TOKEN_SALT = 'user_salt';

    // 用于生成token的自定义盐
    /**
     * 用户信息 (登录成功后才记录)
     * @var UserModel|null $userInfo
     */
    private $userInfo;
    public $token;

    /**
     * 执行用户登录
     * @param array $data
     * @return bool
     * @throws BaseException
     * @throws Exception
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function login(array $data): bool
    {
        // 数据验证
        $this->validate($data);
        // 自动登录注册
        if (!$this->register($data)) {
            return false;
        }
        // 记录登录态
        return $this->setSession();
    }

    /**
     * 数据验证
     * @param array $data
     * @return void
     * @throws BaseException
     */
    private function validate(array $data): void
    {
        // 数据验证
        $validate = new ValidateLogin;
        if (!$validate->check($data)) {
            throwError($validate->getError());
        }
//        // 验证短信验证码是否匹配
//        if (!CaptchaApi::checkSms($data['smsCode'], $data['mobile'])) {
//            throwError('短信验证码不正确');
//        }
    }

    /**
     * 自动登录注册
     * @param array $data
     * @return boolean
     * @throws Exception
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function register(array $data)
    {
        // 查询用户是否已存在
        // 用户存在: 更新用户登录信息
        $userInfo = UserModel::detail([
            'full_name' => $data['full_name'],
            'id_card' => $data['id_card'],
            'is_delete' => 0
        ]);

        if ($userInfo) {
//            $lastSixDigits = substr($userInfo->idnumber, -6);
//
//            //密码为空，且密码与后六位不匹配
//            if (empty($userInfo->password) && $data['password'] != $lastSixDigits) {
//                $this->error = '登录失败, 用户名或密码错误';
//                return false;
//            }
//
//            // 验证密码是否正确
//            if (!empty($userInfo->password) && !password_verify($data['password'], $userInfo->password)) {
//                $this->error = '登录失败, 用户名或密码错误';
//                return false;
//            }

            $this->updateUser($userInfo);
            return true;
        } else {
            $this->error = '登录失败, 未找到相关学员信息，请联系报名机构';
            return false;
        }


//        $lastSixDigits = substr($data['idnumber'], -6);
//        //密码为空，且密码与后六位不匹配
//        if ($data['password'] != $lastSixDigits) {
//            $this->error = '登录失败, 用户名或密码错误';
//            return false;
//        }
//        // 用户不存在: 创建一个新用户
//        $this->createUser($data['full_name'], $data['idnumber'], $data['channel_id']);
//        return true;
    }

    /**
     * 更新用户登录信息
     * @param UserModel $userInfo
     * @param bool $isParty 是否存在第三方用户信息
     * @param array $partyData 用户信息(第三方)
     * @return void
     */
    private function updateUser(UserModel $userInfo): void
    {
        // 用户信息
        $data = [
//            'last_login_time' => time(),
            'store_id' => $this->storeId,
        ];
        // 写入用户信息(第三方)
        // 如果不需要每次登录都更新微信用户头像昵称, 下面4行代码可以屏蔽掉
//        if ($isParty === true && !empty($partyData)) {
//            $partyUserInfo = PartyService::partyUserInfo($partyData, true);
//            $data = array_merge($data, $partyUserInfo);
//        }
        // 更新用户记录
        $userInfo->save($data) !== false;
        // 记录用户信息
        $this->userInfo = $userInfo;
    }

    /**
     * 记录登录态
     * @return bool
     * @throws BaseException
     */
    private function setSession(): bool
    {
        empty($this->userInfo) && throwError('未找到用户信息');
        // 登录的token
        $this->token = $this->makeToken($this->getUserId());
        // 记录缓存, 30天
        Cache::set($this->token, [
            'user' => $this->userInfo,
            'store_id' => $this->storeId,
            'is_login' => true,
        ], 86400 * 30);
        return true;
    }

    /**
     * 获取登录的token
     * @param int $userId
     * @return string
     */
    public static function getToken()
    {
        // 获取请求中的token
        $token = request()->header('Access-Token');
        // 调试模式下可通过param
        if (empty($token)) {
            $token = request()->param('Access-Token');
        }
        // 不存在token报错
        if (empty($token)) {
            return false;
        }
        return $token;
    }

    /**
     * 生成用户认证的token
     * @param int $userId
     * @return string
     */
    private function makeToken(int $userId): string
    {
        $storeId = $this->storeId;
        // 生成一个不会重复的随机字符串
        $guid = get_guid_v4();
        // 当前时间戳 (精确到毫秒)
        $timeStamp = microtime(true);
        // 自定义一个盐
        $salt = self::TOKEN_SALT;
        return md5("{$storeId}_{$timeStamp}_{$userId}_{$guid}_{$salt}");
    }

    /**
     * 当前登录的用户ID
     * @return int
     */
    private function getUserId(): int
    {
        return (int)$this->getUserInfo()['student_user_id'];
    }

    public static function getLoginInfo()
    {
        if (($token = self::getToken()) !== false) {
            return Cache::get($token);
        }
        return false;
    }

    /**
     * 当前登录的用户信息
     */
    public function getUserInfo(): ?UserModel
    {
        return $this->userInfo;
    }

    /**
     * 新增用户
     * @param string $full_name 学员姓名
     * @param bool $idnumber 证件号码
     * @return void
     * @throws Exception
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    private function createUser(string $full_name, string $idnumber, $channel_id): void
    {
        // 用户信息
        $data = [
            'full_name' => $full_name,
            'idnumber' => $idnumber,
            'channel_id' => $channel_id,
            'last_login_time' => time(),
            'store_id' => $this->storeId
        ];

        // 新增用户记录
        $model = new UserModel;
        $model->save($data);

        // 记录用户信息
        $this->userInfo = $model;
    }
}
